package freespiritsocial.io.user.chat

import android.util.Base64
import com.sendbird.android.*
import freespiritsocial.io.user.util.FileUtils
import freespiritsocial.io.user.util.TextUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import me.hgj.jetpackmvvm.base.appContext
import java.io.File
import java.io.IOException
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException

/**
 * 聊天管理者
 */
object ChannelManager {
    var mChannelListQuery: GroupChannelListQuery? = null

    fun createChannel(userId: String?,action: (String,String) -> Unit) {
        GroupChannel.createChannel(GroupChannelParams().apply {
            addUserId(userId)
            setDistinct(true)
        }) { openChannel,e ->
            if (e == null) {
                // Error!
                action(openChannel.url,openChannel.members.find { it.userId == userId }?.nickname ?: "")
            }
        }
    }

    fun createChannel(userId: String?,action: (String?,String?,SendBirdException?) -> Unit) {
        GroupChannel.createChannel(GroupChannelParams().apply {
            addUserId(userId)
            setDistinct(true)
        }) { openChannel,e ->
            action(openChannel?.url,openChannel?.members?.find { it.userId == userId }?.nickname ?: "",e)
        }
    }

    fun enterChannel(mChannelUrl: String,action: (GroupChannel?) -> Unit) {
        GroupChannel.getChannel(mChannelUrl) { channel,e ->
            action(channel)
        }
    }

    suspend fun loadChannelList(): List<GroupChannel> = withContext(Dispatchers.IO) {
        try {
            val appDir = File(appContext.cacheDir,SendBird.getApplicationId())
            appDir.mkdirs()

            val dataFile = File(appDir,TextUtils.generateMD5(SendBird.getCurrentUser().userId + "channel_list").toString() + ".data")

            val content: String = FileUtils.loadFromFile(dataFile)
            content.split("\n".toRegex()).toTypedArray().map {
                BaseChannel.buildFromSerializedData(Base64.decode(it,Base64.DEFAULT or Base64.NO_WRAP)) as GroupChannel
            }
        } catch (e: Exception) {
            emptyList()
        }
    }

    suspend fun saveChannelList(mChannelList: List<GroupChannel>) = withContext(Dispatchers.IO) {
        try {
            val sb = StringBuilder()
            // Save the data into file.
            val appDir = File(appContext.cacheDir,SendBird.getApplicationId())
            appDir.mkdirs()
            val hashFile = File(appDir,TextUtils.generateMD5(SendBird.getCurrentUser().userId + "channel_list").toString() + ".hash")
            val dataFile = File(appDir,TextUtils.generateMD5(SendBird.getCurrentUser().userId + "channel_list").toString() + ".data")
            if (mChannelList.isNotEmpty()) {
                // Convert current data into string.
                var channel: GroupChannel?
                for (i in 0 until mChannelList.size.coerceAtMost(100)) {
                    channel = mChannelList[i]
                    sb.append("\n")
                    sb.append(Base64.encodeToString(channel.serialize(),Base64.DEFAULT or Base64.NO_WRAP))
                }
                // Remove first newline.
                sb.delete(0,1)
                val data = sb.toString()
                val md5 = TextUtils.generateMD5(data)
                try {
                    val content = FileUtils.loadFromFile(hashFile)
                    // If data has not been changed, do not save.
                    if (md5 == content) {
                        return@withContext
                    }
                } catch (e: IOException) {
                    // File not found. Save the data.
                }
                FileUtils.saveToFile(dataFile,data)
                FileUtils.saveToFile(hashFile,md5)
            } else {
                FileUtils.deleteFile(dataFile)
                FileUtils.deleteFile(hashFile)
            }
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
        }
    }

    suspend fun getChannelList(refresh: Boolean,key: String = "") = withContext(Dispatchers.IO) {
        if (refresh) {
            mChannelListQuery = GroupChannel.createMyGroupChannelListQuery()
            mChannelListQuery?.limit = 20
            if (key.isNotEmpty())
                mChannelListQuery?.setSearchFilter(listOf(GroupChannelListQuery.SearchField.MEMBER_NICKNAME),key)
        }
        getChannelList()
    }

    private suspend fun getChannelList() = suspendCancellableCoroutine<List<GroupChannel>> {
        mChannelListQuery?.next { mutableList,sendBirdException ->
            if (sendBirdException != null) {
                return@next it.resumeWithException(sendBirdException)
            }
            it.resume(mutableList)
        }
    }

}